package com.avantis.admin.config.shiro;

import org.apache.shiro.authz.annotation.*;
import org.apache.shiro.spring.security.interceptor.AopAllianceAnnotationsAuthorizingMethodInterceptor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

/**
 * @Author:Shmily
 * @Description:如果方法上没有权限注解，尝试获取类上的默认权限注解。即方法注解优先，在方法没有注解的时候再去类上面读取。
 */
public class YaphetsAuthorizationAttributeSourceAdvisor extends AuthorizationAttributeSourceAdvisor {
    private static final Logger log = LoggerFactory.getLogger(AuthorizationAttributeSourceAdvisor.class);

    private static final Class<? extends Annotation>[] AUTHZ_ANNOTATION_CLASSES =
            new Class[] {
                    RequiresPermissions.class, RequiresRoles.class,
                    RequiresUser.class, RequiresGuest.class, RequiresAuthentication.class
            };

    /**
     * Web 注解
     */
    private static final Class<? extends Annotation>[] WEB_ANNOTATION_CLASSES =
            new Class[] {
                    RequestMapping.class
            };

    /**
     * Create a new AuthorizationAttributeSourceAdvisor.
     */
    public YaphetsAuthorizationAttributeSourceAdvisor() {
        setAdvice(new AopAllianceAnnotationsAuthorizingMethodInterceptor());
    }


    @Override
    public boolean matches(Method method, Class targetClass) {
        boolean flag = super.matches(method, targetClass);
        if(!flag && isAuthzAnnotationPresent(targetClass) && isWebAnnotationPresent(method)){
            flag = true;
        }

        return flag;
    }

    private boolean isAuthzAnnotationPresent(Class<Controller> clazz) {
        for( Class<? extends Annotation> annClass : AUTHZ_ANNOTATION_CLASSES ) {
            Annotation a = AnnotationUtils.findAnnotation(clazz, annClass);
            if ( a != null ) {
                return true;
            }
        }
        return false;
    }


    private boolean isWebAnnotationPresent(Method method) {
        for( Class<? extends Annotation> annClass : WEB_ANNOTATION_CLASSES ) {
            Annotation a = AnnotationUtils.findAnnotation(method, annClass);
            if ( a != null ) {
                return true;
            }
        }
        return false;
    }
}
